package main

import (
	"fmt"
	"sync"
	"time"
)

func main()  {
	//一个goroutine的集合点，等待或发布一个event
	//event是两个或两个以上的goroutine之间的任意信号、
	//cond让goroutine有效的等待信号

	//示例：
	c := sync.NewCond(&sync.Mutex{})   //创建新的cond，NewCond创建一个类型，满足sync.Locker接口，使cond类型以并发安全的方式与goroutine协调
	c.L.Lock() //锁定条件
	for conditionTrue() == false {
		c.Wait()   //等待通知，阻塞通信，goroutine将被暂停
	}
	c.L.Unlock()   //解锁
	//Wait阻塞挂起goroutine，允许其他goroutine在OS线程上运行

	//示例：
	c := sync.NewCond(&sync.Mutex{})   //使用sync.Mutex作为锁
	queue := make([]interface{},0,10)  //创建长度为0切片，用10的容量实例化
	removeFromQueue := func(delay time.Duration) {
		tiem.Sleep(delay)
		c.L.Lock() //再次进入临界区,以便可以修改与条件相关的数据
		queue = queue[1:]  //通过将切片的头部重新分配到第二个项目来模拟对一个项目的排队
		fmt.Println("Removed from queue")
		c.L.Unlock()   //退出条件的临界区，已经成功删除了一个项目
		c.Signal() //让等待的goroutine知道发生的事
	}
	for i:=0;i<10;i++{
		c.L.Lock() //在条件锁存器上调用锁来进入临界区
		for len(queue) == 2 {  //检查循环队列长度
			c.Wait()   //调用Wait，将暂停main goroutine直到一个信号的条件已经发送
		}
		fmt.Println("Adding to queue")
		queue = append(queue,struct{}{})
		go removeFromQueue(1*time.Second)  //创建新的goroutine,将在一秒后删除一个元素
		c.L.Unlock()   //退出临界区，成功进入一个项目
	}


	//示例：
	type Button struct {   //定义一个Button类型，包含一个条件Clicked
		Clicked *sync.Cond
	}
	button := Button{ Clicked: sync.NewCond(&sync.Mutex{})}

	subscribe := func(c *sync.cond,fn func()) {    //定义一个便利构造函数，程序在自己的goroutine上处理来自条件的信号
		var goroutineRunning sync.WaitGroup
		foroutineRunning.Add(1)
		go func() {
			goroutineRunning.Done()
			c.L.Lock()
			defer c.L.Unlock()
			c.Wait()
			fn()
		}()
		goroutineRunning.Wait()
	}

	var clickRegistered sync.WaitGroup //鼠标按键设置的处理程序，反过来调用Cond上Broadcast，
	clickRegistered.Add(3)
	subscribe(button.Clicked,func() {  //创建一个WaitGroup,确保程序在写入stdout之前不会退出
		fmt.Println("Maxinmizing window.")
		clickRegistered.Done()
	})
	subscribe(button.Clicked,func() {  //注册一个程序，当单击按键时，将模拟最大化按钮的窗口
		fmt.Println("Displaying annoying dialog box")
		clickRegistered.Done()
	})
	subscribe(button.Clicked,func() {  //注册一个处理程序，在单击鼠标时模拟显示对话框
		fmt.Println("Mouse clicked.")
		clickRegistered.Done()
	})

	button.Clicked.Broadcast() //模拟一个用户通过单击应用程序的按钮来单击鼠标按键

	clickRegistered.Wait()





}














